﻿#include "RunWidget.h"
#include "ui_RunWidget.h"
#include "CalculateDriver.h"
#include "CalculateDriverFASTSIM.h"

#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKSignalTransfer.h"
#include "FITK_Kernel/FITKAppFramework/FITKComponents.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppSettings.h"
#include "FITK_Kernel/FITKAppFramework/FITKProgramTaskManager.h"
#include "FITK_Kernel/FITKCore/FITKDirFileTools.h"
#include "FITK_Kernel/FITKEasyParam/FITKWidgetComLine.h"
#include "FITK_Kernel/FITKEasyParam/FITKEasyParamWidgetFactory.h"
#include "FITK_Kernel/FITKEasyParam/FITKParameter.h"
#include "FITK_Component/FITKOFDictWriter/FITKOFDictWriterIO.h"
#include "FITK_Component/FITKOFDriver/FITKOFInputInfo.h"
#include "FITK_Interface/FITKInterfaceFlowOF/FITKOFPhysicsData.h"
#include "FITK_Interface/FITKInterfaceFlowOF/FITKOFRunControl.h"
#include "FITK_Interface/FITKInterfaceFlowOF/FITKAbstractOFSolver.h"
#include "FITK_Interface/FITKInterfaceFlowOF/FITKFlowPhysicsHandlerFactory.h"
#include "FITK_Interface/FITKInterfaceMesh/FITKUnstructuredMeshVTK.h"
#include "FITK_Interface/FITKInterfaceIO/FITKAbstractIO.h"
//ADD
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMaterial.h"
#include "FITK_Interface/FITKInterfacePhysics/FITKAbstractMaterial.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMaterialBehavior.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMaterialDensity.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMaterialPlastic.h"
#include "FITK_Interface/FITKInterfaceFlowOF/FITKSimulationParameters.h"
#include"FITK_Kernel/FITKEasyParam/FITKAbstractEasyParam.h"
#include "FITK_Interface/FITKInterfacePhysics/FITKAbstractSection.h"
//数据层
#include "FITK_Kernel/FITKEasyParam/FITKParameter.h"
#include "FITK_Kernel/FITKEasyParam/FITKAbstractEasyParam.h"
#include "FITK_Kernel/FITKEasyParam/FITKParamBool.h"
#include "FITK_Kernel/FITKEasyParam/FITKParamInt.h"
#include "FITK_Kernel/FITKEasyParam/FITKParamDouble.h"
#include "FITK_Kernel/FITKEasyParam/FITKParamString.h"
#include "FITK_Kernel/FITKEasyParam/FITKParamBoolGroup.h"
#include "FITK_Kernel/FITKEasyParam/FITKParamCombox.h"
#include "FITK_Kernel/FITKEasyParam/FITKParamDoubleList.h"
#include "FITK_Kernel/FITKEasyParam/FITKParamRadioGroup.h"
#include "FITK_Kernel/FITKEasyParam/FITKParamLabel.h"

#include <QButtonGroup>
#include <QProcess>
#include <QDir>
#include <QTextStream>
#include <QDomDocument>
#include <QTabBar>
#include <QDebug>
#include <vtkCell.h>
#include <vtkUnstructuredGrid.h>
#include <QMessageBox>
#include <QFileDialog>

#define CPUType "CPUType"
Q_DECLARE_METATYPE(GUI::RunCPUType)

namespace GUI
{
    static RunCPUType _currentCUPType = RunCPUType::Serial;
    static int _currentCUPNum = 4;
    static int _currentDriverID = -1;

    RunWidget::RunWidget(EventOper::ParaWidgetInterfaceOperator* oper, QWidget* parent) :
        GUICalculateWidgetBase(oper,parent)
    {
        _ui = new Ui::RunWidget();
        _ui->setupUi(this);

        init();
    }

    RunWidget::~RunWidget()
    {
        if (_ui) {
            delete _ui;
            _ui = nullptr;
        }
    }

    void RunWidget::init()
    {
        if (_physicsData) {
            _runConObj = _physicsData->getRunControl();
        }
        updataTime();
        updateOutput();
        initCPU();
    }

    void RunWidget::showEvent(QShowEvent * event)
    {
        Q_UNUSED(event);
        int width = _ui->tabWidget->width();
        int tabCount = _ui->tabWidget->count();
        int tabWidth = width / tabCount;
        _ui->tabWidget->tabBar()->setStyleSheet(QString("QTabBar::tab{width:%1px;height:30px;}").arg(tabWidth));
    }

    void RunWidget::resizeEvent(QResizeEvent * event)
    {
        Q_UNUSED(event);
        int width = _ui->tabWidget->width();
        int tabCount = _ui->tabWidget->count();
        int tabWidth = width / tabCount;
        _ui->tabWidget->tabBar()->setStyleSheet(QString("QTabBar::tab{width:%1px;height:30px;}").arg(tabWidth));
    }

    void RunWidget::slotCPUChange(QAbstractButton * button)
    {
        if (button == nullptr)return;
        _currentCUPType = button->property(CPUType).value<RunCPUType>();
        updateCPU();
    }

    void RunWidget::slotProcessFinish()
    {
        setRunType(false);
    }

    void RunWidget::on_spinBox_NumOfPro_valueChanged(int arg1)
    {
        _currentCUPNum = arg1;
        updateCPU();
    }

    void RunWidget::on_pushButton_Stop_clicked()
    {
        auto app = dynamic_cast<AppFrame::FITKApplication*>(qApp);
        auto proGramManager = app->getProgramTaskManager();
        auto driver = proGramManager->getDataByID(_currentDriverID);
        if (driver) {
            driver->stop();
        }
        setRunType(false);
    }

    // 调用终端运行openfoam求解器命令
//    void RunWidget::on_pushButton_Run_clicked()
//    {
//        //工作路径获取
//        QString workDir = "";
//        if (FITKAPP->getAppSettings()) {
//            workDir = FITKAPP->getAppSettings()->getWorkingDir();
//        }
//        if (workDir.isEmpty()) workDir = QApplication::applicationDirPath() + "/../WorkDir";
//        QString caseDir = workDir + "/case";

//        //清理字典文件
//        if (!clearCasePath(caseDir)) {
//            emit FITKAPP->getSignalTransfer()->outputMessageSig(3, tr("Clear failed!"));
//            return;
//        }
//        //写出字典文件
//        if (!writeCase(caseDir)) {
//            emit FITKAPP->getSignalTransfer()->outputMessageSig(3, tr("Write failed!"));
//            return;
//        }
//        //写出启动脚本
//        QString shPath = creatStartSh(workDir, caseDir);
//        if (shPath.isEmpty()) {
//            emit FITKAPP->getSignalTransfer()->outputMessageSig(3, tr("Create sh failed!"));
//            return;
//        }

//        auto app = dynamic_cast<AppFrame::FITKApplication*>(qApp);
//        auto proGramManager = app->getProgramTaskManager();
//        AppFrame::FITKProgramInputInfo* info = new FoamDriver::FITKOFInputInfo();
//        QStringList args;
//        args << shPath;
//        info->setArgs(args);
//        auto progam = proGramManager->createProgram(1, "CalculateDriver", info);
//        if (!progam) return;
//        CalculateDriver* calDriver = dynamic_cast<CalculateDriver*>(progam);
//        if (calDriver) {
//            calDriver->setExecProgram("/bin/bash");
//            _currentDriverID = calDriver->getDataObjectID();
//        }
//        //启动进程
//        connect(progam, SIGNAL(sig_Finish()), this, SLOT(slotProcessFinish()));
//        connect(progam, &CalculateDriver::sig_Finish, []() {
//            auto app = dynamic_cast<AppFrame::FITKApplication*>(qApp);
//            auto proGramManager = app->getProgramTaskManager();
//            if (proGramManager)proGramManager->removeDataByID(_currentDriverID);
//        });

//        setRunType(true);
//        progam->start();
//    }

    // 调用自研求解器命令
    void RunWidget::on_pushButton_Run_clicked()
    {
        //工作路径获取
        QString workDir = "";
        if (FITKAPP->getAppSettings()) {
            workDir = FITKAPP->getAppSettings()->getWorkingDir();
        }
        if (workDir.isEmpty()) workDir = QDir::cleanPath(QApplication::applicationDirPath() + "/../WorkDir");
        QString caseDir = QDir::cleanPath(workDir + "/case");

        // 求解器路径获取
        //QString solverPath = QDir::cleanPath(QApplication::applicationDirPath() + "/../Solver/TetSingleOpenMP_MPM/OpenMPMPM.exe");
        QString solverPath = _ui->lineEdit_4->text();
        QFileInfo info_solver(solverPath);
        if((!info_solver.exists()) || (!info_solver.isFile())) {
            emit FITKAPP->getSignalTransfer()->outputMessageSig(3, tr("Warning :  Solver Path Error! Solve Path : %1").arg(solverPath));
            return;
        }

        //写出xml文件
        if (!writeCase_xml(caseDir)) {
            emit FITKAPP->getSignalTransfer()->outputMessageSig(3, tr("Write xml failed!"));
            return;
        }

        // 将当前的工作目录设置为workDir所指向的目录
        QString oldDir	  = "";
        QDir dir(caseDir);
        if(dir.exists() && (!caseDir.isEmpty())) {
             oldDir = QDir::currentPath();
             QDir::setCurrent(caseDir);
        }
//        //将frition_coef.xml文件复制到Case算例的三个xml文件放到一起
//        QString args = _solver->getParameter();
//        args.replace("%modelpath%", startPath, Qt::CaseInsensitive);

        // 获取求解器调用控制参数
        auto app = dynamic_cast<AppFrame::FITKApplication*>(qApp);
        auto proGramManager = app->getProgramTaskManager();
        AppFrame::FITKProgramInputInfo* info = new FoamDriver::FITKOFInputInfo();
        QStringList args;
        //args << "in -t 2"; // _ui->arguementsLineEdit->text()
        args << _ui->lineEdit_2->text();
        info->setArgs(args);
        auto progam = proGramManager->createProgram(1, "CalculateDriverFASTSIM", info);
        if (!progam) return;
        CalculateDriverFASTSIM* calDriverFASTSIM = dynamic_cast<CalculateDriverFASTSIM*>(progam);
        if (calDriverFASTSIM) {
            calDriverFASTSIM->setExecProgram(solverPath);
            _currentDriverID = calDriverFASTSIM->getDataObjectID();
        }
        //启动进程
        connect(progam, SIGNAL(sig_Finish()), this, SLOT(slotProcessFinish()));
        connect(progam, &CalculateDriver::sig_Finish, []() {
            auto app = dynamic_cast<AppFrame::FITKApplication*>(qApp);
            auto proGramManager = app->getProgramTaskManager();
            if (proGramManager)proGramManager->removeDataByID(_currentDriverID);
        });

        setRunType(true);
        progam->start();

        if(!oldDir.isEmpty())
            QDir::setCurrent(oldDir);
    }

    void RunWidget::updataTime()
    {
        if (_runConObj == nullptr)return;
        Core::FITKParameter* tiemPara = _runConObj->getTimeControl();
        for (auto data : tiemPara->getParameter()) {
            if(data == nullptr)continue;
            QWidget* widget = nullptr;
            if (data->getParamType() == Core::FITKAbstractEasyParam::FITKEasyParamType::FEPBoolGroup) {
                widget = Core::FITKEasyParamWidgetFactory::createWidget(data, this);
            }
            else {
                widget = new Core::FITKWidgetComLine(data, this);
            }
            _ui->verticalLayout_Time->addWidget(widget);
        }

    }

    void RunWidget::updateOutput()
    {
        if (_runConObj == nullptr)return;
        Core::FITKParameter* outPara = _runConObj->getOutputControl();
        for (auto data : outPara->getParameter()) {
            if (data == nullptr)continue;
            QWidget* widget = nullptr;
            if (data->getParamType() == Core::FITKAbstractEasyParam::FITKEasyParamType::FEPBoolGroup) {
                widget = Core::FITKEasyParamWidgetFactory::createWidget(data, this);
            }
            else {
                widget = new Core::FITKWidgetComLine(data, this);
            }
            _ui->verticalLayout_Output->addWidget(widget);
        }
       connect(_ui->pushButton, &QPushButton::clicked, this, &RunWidget::onOpenFileButtonClicked);
    }

    void RunWidget::onOpenFileButtonClicked()
    {
        // 打开文件对话框
        QString filePath = QFileDialog::getOpenFileName(this, "Open File", "", "All Files (*.*);;Text Files (*.txt)");
        // 判断是否选择了文件
        if (!filePath.isEmpty()) {
            QMessageBox::information(this, "File Selected", "You selected:\n" + filePath);
            _ui->lineEdit_4->setText(filePath);
            QString name = filePath.section('/', -1);
            _ui->lineEdit->setText(name);
        } else {
            QMessageBox::warning(this, "No File Selected", "You didn't select any file.");
        }
    }


    void RunWidget::initCPU()
    {
        QButtonGroup* group = new QButtonGroup(this);
        _ui->radioButton_serial->setProperty(CPUType, QVariant::fromValue(RunCPUType::Serial));
        _ui->radioButton_parallel->setProperty(CPUType, QVariant::fromValue(RunCPUType::Parallel));
        group->addButton(_ui->radioButton_serial);
        group->addButton(_ui->radioButton_parallel);
        connect(group, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(slotCPUChange(QAbstractButton*)));

        updateCPU();

        // 监听 Type 选项变化
        connect(_ui->Type, SIGNAL(currentTextChanged(const QString&)), this, SLOT(onTypeChanged(const QString&)));

        //线程事件未结束，重新绑定结束事件与设置界面
        auto app = dynamic_cast<AppFrame::FITKApplication*>(qApp);
        auto proGramManager = app->getProgramTaskManager();
        auto progam = proGramManager->getDataByID(_currentDriverID);
        if (progam) {
            //启动进程
            connect(progam, SIGNAL(sig_Finish()), this, SLOT(slotProcessFinish()));
        }
        setRunType(progam);
    }

    void RunWidget::updateCPU()
    {
        switch (_currentCUPType) {
        case GUI::RunCPUType::Serial: {
//            _ui->spinBox_NumOfPro->setEnabled(false);
//            _ui->spinBox_NumOfPro_2->setEnabled(false);
//            _ui->Type->setEnabled(false);
//            _ui->radioButton_serial->setChecked(true);
            _ui->spinBox_NumOfPro->setVisible(false);
            _ui->spinBox_NumOfPro_2->setVisible(false);
            _ui->Type->setVisible(false);
            _ui->label->setVisible(false);
            _ui->label_3->setVisible(false);
            _ui->label_4->setVisible(false);
            _ui->radioButton_serial->setChecked(true);
            break;
        }
        case GUI::RunCPUType::Parallel: {
            _ui->spinBox_NumOfPro->setVisible(true);
            _ui->spinBox_NumOfPro_2->setVisible(true);
            _ui->spinBox_NumOfPro->setEnabled(false);
            _ui->spinBox_NumOfPro_2->setEnabled(false);
            _ui->Type->setVisible(true);
            _ui->label->setVisible(true);
            _ui->label_3->setVisible(true);
            _ui->label_4->setVisible(true);
            _ui->radioButton_parallel->setChecked(true);
            // 确保 Type 的初始状态同步
            onTypeChanged(_ui->Type->currentText());
            break;
        }
        }

        _ui->spinBox_NumOfPro->setValue(_currentCUPNum);
    }

    void RunWidget::onTypeChanged(const QString& text)
    {
        if (text == "MPI") {
            _ui->label->setVisible(true);
            _ui->Type->setVisible(true); // 选项框可见
            _ui->spinBox_NumOfPro->setEnabled(true);
            _ui->spinBox_NumOfPro_2->setEnabled(false);
            _ui->label_3->setVisible(true);
            _ui->label_4->setVisible(true);
        } else if (text == "OpenMP") {
            _ui->label->setVisible(true);
            _ui->Type->setVisible(true); // 选项框可见
            _ui->spinBox_NumOfPro->setEnabled(false);
            _ui->spinBox_NumOfPro_2->setEnabled(true);
            _ui->label_3->setVisible(true);
            _ui->label_4->setVisible(true);
        } else if (text == "MPI+OpenMP"){
            // 默认状态
            _ui->spinBox_NumOfPro->setEnabled(true);
            _ui->spinBox_NumOfPro_2->setEnabled(true);
            _ui->Type->setVisible(true);
            _ui->label->setVisible(true);
            _ui->label_3->setVisible(true);
            _ui->label_4->setVisible(true);
        }
    }

    bool RunWidget::clearCasePath(QString casePath)
    {
        QDir dir(casePath);
        // 设置过滤器，只获取目录
        dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);

        // 获取目录列表
        QStringList directories = dir.entryList();

        //清除非system与constant文件夹
        for (auto path : directories) {
            if(path == "system")continue;
            if(path == "constant")continue;
            Core::RemoveDir(casePath + "/" + path);
        }

        return true;
    }

    bool RunWidget::writeCase(QString casePath)
    {
        auto dicWriComp = FITKAPP->getComponents()->getComponentTByName<IO::FITKOFDictWriterIO>("IO::FITKOFDictWriterIO");
        if (dicWriComp == nullptr)return false;

        if (!dicWriComp->setFilePath(casePath)) {
            Core::CreateDir(casePath);
            dicWriComp->setFilePath(casePath);
        }
        dicWriComp->setPhysicsDictW();
        if (!dicWriComp->exec())return false;

        return true;
    }

    bool RunWidget::writeCase_xml(QString casePath)
    {
//        auto dicWriComp = FITKAPP->getComponents()->getComponentTByName<IO::FITKOFDictWriterIO>("IO::FITKOFDictWriterIO");
//        if (dicWriComp == nullptr)return false;

        QDir dir;
        if (!dir.exists(casePath))
            dir.mkdir(casePath);//在指定路径下创建一个目录

        QString filename_model;
        QString filename_mesh;
//        QString filename_geo;
        QString filename_material;

        filename_mesh = casePath + "/" + "meshdata.xml";
        setFileName(filename_mesh);
        write_xml_meshdata();

        filename_material=casePath+"/" + "material.xml";
        setFileName(filename_material);
        write_xml_material();

        filename_model=casePath+"/" + "model.xml";
        setFileName(filename_model);
        write_xml_model();

        return true;
    }

     QString RunWidget::creatStartSh(QString workDir, QString caseDir)
     {
        QString foamRun, foamName;
        if (_factoryData == nullptr)return "";
        bool isSetFields = _factoryData->isExecuteSetFields();
        Interface::FITKAbstractOFSolver* curSolver = _physicsData->getSolver();
        if (curSolver) {
            foamName = curSolver->getSolverCommand();
        }
        
        //脚本生成
        switch (_currentCUPType) {
        case GUI::RunCPUType::Serial:break;
        case GUI::RunCPUType::Parallel: {
            foamRun += QString("mpirun -np %1 ").arg(_currentCUPNum);
            break;
        }
        }
        foamRun += QString("%1 -case %2").arg(foamName).arg(caseDir);

        QString shFilePath = workDir + "/startOpenFoam.sh";
        QFile file(shFilePath);
        // 打开文件进行写操作
        if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return "";
        // 创建一个 QTextStream 对象来写入文本
        QTextStream out(&file);
        // 写入字符串到文件
        if (isSetFields) {
            out << QString("setFields -case %1").arg(caseDir);
            out << QStringLiteral("\n");
        }
        out << foamRun;
        // 关闭文件
        file.close();
        return shFilePath;
     }

     void RunWidget::setRunType(bool isRun)
     {
        if (isRun) {
            _ui->progressBar->show();
            _ui->pushButton_Run->setEnabled(false);
            _ui->pushButton_Stop->setEnabled(true);
        }
        else
        {
            _ui->progressBar->hide();
            _ui->pushButton_Run->setEnabled(true);
            _ui->pushButton_Stop->setEnabled(false);
        }
     }

     void RunWidget::write_xml_meshdata()
     {
         if (!_file.open(QIODevice::WriteOnly | QIODevice::Text))//_file在105行创建的
             return;
         _doc = new QDomDocument;
         QDomProcessingInstruction instruction = _doc->createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
         _doc->appendChild(instruction);
         QDomElement root = _doc->createElement("DISO_FILE_1.0");
         _doc->appendChild(root);
         //_meshData->writeToProjectFile(_doc, &root);
         writeToProjectFileNOMeshSetButWirteToolForceInformation(_doc, &root);
         _stream = new QTextStream(&_file);
         _doc->save(*_stream, 4);

         QString filename_model_temp = _filename.remove("meshdata.xml").toLocal8Bit();
         QString filename_model_json = filename_model_temp + "meshdata.json";
         QFile temp_file(filename_model_json);
         if (temp_file.open(QIODevice::ReadOnly))
         {
             temp_file.remove();
             temp_file.close();
         }
         _file.close();
     }

     void RunWidget::write_xml_material()
     {
         if (!_file.open(QIODevice::WriteOnly | QIODevice::Text))//_file在105行创建的
             return;
         _doc = new QDomDocument;
         QDomProcessingInstruction instruction = _doc->createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
         _doc->appendChild(instruction);
         QDomElement root = _doc->createElement("DISO_FILE_1.0");
         _doc->appendChild(root);
         writeToProjectMaterialFile(_doc,&root);
         _stream = new QTextStream(&_file);
         _doc->save(*_stream, 4);
         _file.close();
     }

     void RunWidget::write_xml_model()
     {
         if (!_file.open(QIODevice::WriteOnly | QIODevice::Text))
             return;
         _doc = new QDomDocument;
         QDomProcessingInstruction instruction = _doc->createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
         _doc->appendChild(instruction);

         if(_ui->Type->currentText()=="MPI+OpenMP"||_ui->Type->currentText()=="OpenMP")
         {
          //写入MPI  OpenMP混合求解
          QDomElement solverEle = _doc->createElement("SolverData");
          QDomAttr data = _doc->createAttribute("OpenMP");
          data.setValue(QString::number(_ui->spinBox_NumOfPro_2->value()));
          solverEle.setAttributeNode(data);
          _doc->appendChild(solverEle);
         }

         QDomElement root = _doc->createElement("DISO_FILE_1.0");
         _doc->appendChild(root);
         this->writeToProjectModelFile(_doc,&root);
         _stream = new QTextStream(&_file);//将_file作为输出流，可以将数据写入到文件中
         _doc->save(*_stream, 4);//将XML文件保存到指定的流中 缩进的空格数
         _file.close();
     }

     QDomElement& RunWidget::writeToProjectFileNOMeshSetButWirteToolForceInformation(QDomDocument* doc, QDomElement* parent)
     {
         QDomElement meshNode = doc->createElement("Mesh");

         auto meshdate = FITKAPP->getGlobalData()->getMeshDataFASTSIM<Interface::FITKUnstructuredMeshVTK>();
         auto manager = meshdate->getBoundaryMeshManager();
         const int n = manager->getDataCount();

         QDomElement meshKernalList = doc->createElement("Kernel");
         for (int i = 0; i < n; ++i)
         {
             //MeshKernal* k = _meshList.at(i);
             auto meshdate = FITKAPP->getGlobalData()->getMeshDataFASTSIM<Interface::FITKUnstructuredMeshVTK>();
             auto manager = meshdate->getBoundaryMeshManager();
             auto k = manager->getDataByIndex(i);

             writeToProjectFileMesh(doc, &meshKernalList,k);
         }
         //MODELFORCEID
         meshNode.appendChild(meshKernalList);
//         const int nset = _setList.size();
//         QDomElement setList = doc->createElement("Set");
//         for (int i = 0; i < nset; ++i)
//         {
//             auto meshdate = FITKAPP->getGlobalData()->getMeshDataFASTSIM<Interface::FITKUnstructuredMeshVTK>();
//             auto manager = meshdate->getBoundaryMeshManager();
//             auto s = manager->getDataByIndex(i);
//             QString name = s->getDataObjectName();
//             writeToProjectFileSet(doc, &setList,name);
//         }
//         meshNode.appendChild(setList);
         parent->appendChild(meshNode);
         return meshNode;
     }

     QDomElement& RunWidget::writeToProjectFileMesh(QDomDocument* doc, QDomElement* parent,Interface::FITKUnstructuredMeshVTK *k)
     {
         QString name = k->getDataObjectName();
         int id = k->getDataObjectID();
         QDomElement kernelele = doc->createElement("MeshKernel");
         QDomAttr idAttr = doc->createAttribute("ID");
         idAttr.setValue(QString::number(id));
         kernelele.setAttributeNode(idAttr);
         QDomAttr visible = doc->createAttribute("Visible");
         visible.setValue("True");
         if (!_visible) visible.setValue("False");
         kernelele.setAttributeNode(visible);
         QDomElement nameele = doc->createElement("Name");
         QDomText nameText = doc->createTextNode(name);
         nameele.appendChild(nameText);
         kernelele.appendChild(nameele);

         if (!_path.isEmpty())
         {
             QDomElement pathele = doc->createElement("Path");
             QDomText pathtext = doc->createTextNode(_path);
             pathele.appendChild(pathtext);
             kernelele.appendChild(pathele);
         }

         QDomElement idoffset = doc->createElement("IDOffset");
         QDomAttr nodeid = doc->createAttribute("Node");
         nodeid.setValue(QString::number(_pointIDOffset));
         QDomAttr cellid = doc->createAttribute("Cell");
         cellid.setValue(QString::number(_cellIDOffset));
         idoffset.setAttributeNode(nodeid);
         idoffset.setAttributeNode(cellid);
         kernelele.appendChild(idoffset);
         //节点
         QDomElement nodeListEle = doc->createElement("NodeList");
         //const int nNode = _mesh->GetNumberOfPoints();
         const int nNode = k->getGrid()->GetNumberOfPoints();
         _pointIDOffset += nNode;
         for (int i = 0; i < nNode; ++i)
         {
             //double* coor = _mesh->GetPoint(i);
             double* coor = k->getGrid()->GetPoint(i);                 //获取节点数据
             QDomElement node = doc->createElement("Node");
             QString s = QString("%1,%2,%3,%4,%5").arg(name).arg(i).arg(coor[0]).arg(coor[1]).arg(coor[2]);//节点名称和编号及其对应的X、Y、Z的坐标值
             QDomText nodetext = doc->createTextNode(s);
             node.appendChild(nodetext);
             nodeListEle.appendChild(node);
         }
         kernelele.appendChild(nodeListEle);
         //单元
         QDomElement elementListEle = doc->createElement("ElementList");
         //const int nele = _mesh->GetNumberOfCells();
         const int nele = k->getGrid()->GetNumberOfCells();
         _cellIDOffset += nele;
         for (int i = 0; i < nele; ++i)
         {
             //vtkCell* cell = _mesh->GetCell(i);
             vtkCell* cell = k->getGrid()->GetCell(i);
//             QString stype = vtkCellTYpeToString((VTKCellType)cell->GetCellType());
             QString stype = "UNKNOW";
             switch ((VTKCellType)cell->GetCellType())
             {
             case VTK_LINE:
                 stype = "LINE2"; break;
             case VTK_TRIANGLE:
                 stype = "TRI3"; break;
             case VTK_QUAD:
                 stype = "QUAD4"; break;
             case VTK_TETRA:
                 stype = "TET4"; break;
             case VTK_HEXAHEDRON:
                 stype = "HEX8"; break;
             case VTK_WEDGE:
                 stype = "WED6"; break;
             case VTK_PYRAMID:
                 stype = "PYR5"; break;
             default:
                 break;
             }
             QString text = QString("%1,%2,%3").arg(name).arg(i).arg(stype);//单元的编号和单元的类型
             vtkIdList* ids = cell->GetPointIds();
             const int n = ids->GetNumberOfIds();
             QDomElement element = doc->createElement("Element");
             for (int i = 0; i < n; ++i)
             {
                 int id = ids->GetId(i);
                 text.append(",");
                 text.append(QString("%1").arg(id));
             }
             QDomText eletext = doc->createTextNode(text);
             element.appendChild(eletext);
             elementListEle.appendChild(element);
         }
         kernelele.appendChild(elementListEle);
         parent->appendChild(kernelele);
         return kernelele;
     }

     QDomElement& RunWidget::writeToProjectMaterialFile(QDomDocument* doc, QDomElement* parent)
     {
        QDomElement mroot = doc->createElement("Materials");
        auto materialmanager = FITKAPP->getGlobalData()->getMaterialData<Interface::FITKMaterialManager>();
        const int n = materialmanager->getDataCount();//材料的个数
        int index = -1;
        for (int i = 0; i < n; ++i)
        {
            auto k = materialmanager->getDataByIndex(i);
            index = i;
            writeToProjectFileMaterial(doc,&mroot,k,index);
        }
        parent->appendChild(mroot);
        return mroot;
     }

     QDomElement& RunWidget::writeToProjectFileMaterial(QDomDocument* doc, QDomElement* parent,Interface::FITKAbstractMaterial *k,int &index)
     {
         QDomElement maele = doc->createElement("Material");
         QString materialname = k->getDataObjectName();
         //int mat_ID =index+1;
         int mat_ID = k->getMaterialID();
         int mat_ID2= mat_ID/2;
         maele.setAttribute("Name",materialname);
         maele.setAttribute("Type", materialname);
         maele.setAttribute("ID", mat_ID2);

         Interface::FITKAbaMaterial* objMat = dynamic_cast<Interface::FITKAbaMaterial*>(k);
         QList<Interface::FITKAbaMaterialBehavior*> m_materialBehaviors = objMat->getMaterialBeahviors();
         int ncount = m_materialBehaviors.count();
         for (int i =0 ;i< ncount ; i++) {

             QDomElement ele;
             Interface::FITKAbaMaterialBehavior* item = objMat->getMaterialBeahviors()[i];
             if (item == nullptr) continue;

              auto behaviorType = item->getMaterialBehaviorType();
              switch (behaviorType)
              {
              case Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::None:
                  break;
              case Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Density:
              {
                  Interface::FITKAbaMaterialDensity* d = dynamic_cast<Interface::FITKAbaMaterialDensity*>(item);
                  ele = doc->createElement("Parameter");
                  double densityvalue = d->getMassDensity();
                  this->writevalueToMaterialXMLFile(doc,&ele,"DENSITY",QString::number(densityvalue),"Kg/m3","double");
                  maele.appendChild(ele);
              }
              case Interface::FITKAbaMaterialBehaviorEnum::FITKAbaMaterialBehaviorType::Plastic:
              {
                  Interface::FITKAbaMaterialPlastic* d = dynamic_cast<Interface::FITKAbaMaterialPlastic*>(item);
                  if(!d)break;

                  ele = doc->createElement("Parameter");
                  double YOUNGMD = d->getCoiningYOUNGMD();
                  this->writevalueToMaterialXMLFile(doc,&ele,"YOUNGMD",QString::number(YOUNGMD),"MPa" ,"double");
                  maele.appendChild(ele);
                  ele = doc->createElement("Parameter");
                  double POISSONR = d->getCoiningPOISSONR();
                  this->writevalueToMaterialXMLFile(doc,&ele,"POISSONR",QString::number(POISSONR),"","double");
                  maele.appendChild(ele);
                  ele = doc->createElement("Parameter");
                  double COEFFICA = d->getCoiningCOEFFICA();
                  this->writevalueToMaterialXMLFile(doc,&ele,"COEFFICA",QString::number(COEFFICA),"MPa","double");
                  maele.appendChild(ele);
                  ele = doc->createElement("Parameter");
                  double HARDENN = d->getCoiningHARDENN();
                  this->writevalueToMaterialXMLFile(doc,&ele,"HARDENN",QString::number(HARDENN),"","double");
                  maele.appendChild(ele);
                  ele = doc->createElement("Parameter");
                  double YIELDSST = d->getCoiningYIELDSST();
                  maele.appendChild(ele);
                  this->writevalueToMaterialXMLFile(doc,&ele,"YIELDSST",QString::number(YIELDSST),"MPa","double");
                  maele.appendChild(ele);
                  ele = doc->createElement("Parameter");
                  //double YIELDSST = d->getCoiningYIELDSST();
                  maele.appendChild(ele);
                  this->writevalueToMaterialXMLFile(doc,&ele,"ANISOR00",QString::number(2.5820),"","double");
                  maele.appendChild(ele);
                  ele = doc->createElement("Parameter");
                  //double YIELDSST = d->getCoiningYIELDSST();
                  maele.appendChild(ele);
                  this->writevalueToMaterialXMLFile(doc,&ele,"ANISOR45",QString::number(1.9210),"","double");
                  maele.appendChild(ele);
                  ele = doc->createElement("Parameter");
                  //double YIELDSST = d->getCoiningYIELDSST();
                  maele.appendChild(ele);
                  this->writevalueToMaterialXMLFile(doc,&ele,"ANISOR90",QString::number(2.1930),"","double");
                  maele.appendChild(ele);
              }
              default:
                  break;
              }
         }
         parent->appendChild(maele);
         return maele;
     }

     QDomElement& RunWidget::writeToProjectModelFile(QDomDocument* doc, QDomElement* parent)
     {
         QDomElement modelElement = doc->createElement("ModelData");

         auto modeldata = FITKAPP->getGlobalData()->getPhysicsData<Interface::FITKOFPhysicsData>();
         Interface::FITKSimulationParameters* simuparas =modeldata->getSimulationParameters();        
         this->writeToProjectFileModel(doc,&modelElement,simuparas);
         parent->appendChild(modelElement);
         return modelElement;
     }

     QDomElement& RunWidget::writeToProjectFileModel(QDomDocument* doc, QDomElement* ele,Interface::FITKSimulationParameters *k)
     {
         QDomElement modelEle = doc->createElement("Model");
         modelEle.setAttribute("ID", QString::number(1));
         modelEle.setAttribute("Type", "Type1");

         QDomElement name = doc->createElement("Name");
         QDomText nametext = doc->createTextNode("Case_1");
         name.appendChild(nametext);
         modelEle.appendChild(name);

         //材料暂时先这样，后面再写
         QDomElement propele = doc->createElement("Material");
         auto physicsdata= FITKAPP->getGlobalData()->getPhysicsData<Interface::FITKOFPhysicsData>();
         auto section = physicsdata->getSectionManager();
         int ncount = section->getDataCount();

         for (int i =0 ; i<ncount ; i++){
             QDomElement mc = doc->createElement("MaterialInfo");
             QDomAttr setattr = doc->createAttribute("ComponentID");
             QDomAttr propattr = doc->createAttribute("MaterialID");
             QDomAttr setnamettr=doc->createAttribute("ComponentName");
             Interface::FITKAbstractSection* ksection = section->getDataByIndex(i);
             int MaterialID=ksection->GetMatrialIDTemp();
             int MaterialID2=MaterialID/2;

             int ComponentID = ksection->getComponentID();

             QString ComponentName = ksection->getComponentName();

             setattr.setValue(QString::number(ComponentID));
             propattr.setValue(QString::number(MaterialID2));
             setnamettr.setValue(ComponentName);
             mc.setAttributeNode(setattr);
             mc.setAttributeNode(propattr);
             mc.setAttributeNode(setnamettr);
             propele.appendChild(mc);
             modelEle.appendChild(propele);
         }


         //写仿真参数
         QDomElement configele = doc->createElement("ConfigData");

         Core::FITKParameter* ctrlparas = k->getControlParameters();
         QDomElement dataele_1 = doc->createElement("Data");
         dataele_1.setAttribute("ID", 2);
         int count = ctrlparas->getDataCount();
         for (int i =0 ; i<count ; i++)
         {
             Core::FITKAbstractEasyParam* para = ctrlparas->getDataByIndex(i);
             if (!para)continue;
             int paraType = para->getParamType();
             if (paraType == Core::FITKAbstractEasyParam::FITKEasyParamType::FEPBool)
             {
                 Core::FITKParamBool* paraBool = dynamic_cast<Core::FITKParamBool*>(para);
                 if (!paraBool) continue;
                 this->parameterBoolW(doc,& dataele_1 ,paraBool);
             }
             else if (paraType == Core::FITKAbstractEasyParam::FITKEasyParamType::FEPCombox)
             {
                 Core::FITKParamCombox* paraCombox = dynamic_cast<Core::FITKParamCombox*>(para);
                 if (!paraCombox) continue;
                 this->parameterComboxW(doc,& dataele_1,paraCombox);
             }
             else if (paraType == Core::FITKAbstractEasyParam::FITKEasyParamType::FEPDouble)
             {
                 Core::FITKParamDouble* paraDouble = dynamic_cast<Core::FITKParamDouble*>(para);
                 if (!paraDouble) continue;
                 this->parameterDoubleW(doc,& dataele_1,paraDouble);
             }
             else if (paraType == Core::FITKAbstractEasyParam::FITKEasyParamType::FEPInt)
             {
                 Core::FITKParamInt* paraInt = dynamic_cast<Core::FITKParamInt*>(para);
                 if (!paraInt) continue;
                 this->parameterIntW(doc,& dataele_1,paraInt);
             }
         }
         configele.appendChild(dataele_1);

         Core::FITKParameter* actionparas = k->getAction();
         QDomElement dataele_2 = doc->createElement("Data");
         dataele_2.setAttribute("ID", 1);
         count = actionparas->getDataCount();
         for (int i =0 ; i<count ; i++)
         {
             Core::FITKAbstractEasyParam* para = actionparas->getDataByIndex(i);
             if (!para)continue;
             int paraType = para->getParamType();
             if (paraType == Core::FITKAbstractEasyParam::FITKEasyParamType::FEPBool)
             {
                 Core::FITKParamBool* paraBool = dynamic_cast<Core::FITKParamBool*>(para);
                 if (!paraBool) continue;
                 this->parameterBoolW(doc,& dataele_2 ,paraBool);
             }
             else if (paraType == Core::FITKAbstractEasyParam::FITKEasyParamType::FEPCombox)
             {
                 Core::FITKParamCombox* paraCombox = dynamic_cast<Core::FITKParamCombox*>(para);
                 if (!paraCombox) continue;
                 this->parameterComboxW(doc,& dataele_2,paraCombox);
             }
             else if (paraType == Core::FITKAbstractEasyParam::FITKEasyParamType::FEPDouble)
             {
                 Core::FITKParamDouble* paraDouble = dynamic_cast<Core::FITKParamDouble*>(para);
                 if (!paraDouble) continue;
                 this->parameterDoubleW(doc,& dataele_2,paraDouble);
             }
             else if (paraType == Core::FITKAbstractEasyParam::FITKEasyParamType::FEPInt)
             {
                 Core::FITKParamInt* paraInt = dynamic_cast<Core::FITKParamInt*>(para);
                 if (!paraInt) continue;
                 this->parameterIntW(doc,& dataele_2,paraInt);
             }
         }
         configele.appendChild(dataele_2);

         modelEle.appendChild(configele);
         ele->appendChild(modelEle);
         return modelEle;
     }

     void RunWidget::writevalueToMaterialXMLFile(QDomDocument* doc,QDomElement* ele,QString describe,QString value,QString unit,QString Type)
     {
         QDomAttr visattr = doc->createAttribute("Visible");
         QString vis = "true";//暂时默认为true
         visattr.setValue(vis);
         ele->setAttributeNode(visattr);

         QDomAttr desAttr = doc->createAttribute("Describe");
         desAttr.setValue(describe);
         ele->setAttributeNode(desAttr);

         QDomAttr tyattr = doc->createAttribute("Type");
         tyattr.setValue(Type);
         ele->setAttributeNode(tyattr);

         QDomAttr editattr = doc->createAttribute("Editable");
         editattr.setValue("True");
         ele->setAttributeNode(editattr);

         QDomAttr chineAttr = doc->createAttribute("Chinese");
         chineAttr.setValue("");
         ele->setAttributeNode(chineAttr);

         QDomAttr uattr = doc->createAttribute("Unit");
         uattr.setValue(unit);
         ele->setAttributeNode(uattr);

         QDomAttr attr = doc->createAttribute("Value");
         attr.setValue(value);
         ele->setAttributeNode(attr);

         QDomElement rangeele = doc->createElement("Range");
         QString sr = QString("%1,%2").arg(-1e+66).arg(1e+66);
         QDomText rtext = doc->createTextNode(sr);
         rangeele.appendChild(rtext);
         ele->appendChild(rangeele);

         QDomElement accele = doc->createElement("Accuracy");
         QDomText acctext = doc->createTextNode(QString::number(4));
         accele.appendChild(acctext);
         ele->appendChild(accele);
     }

     void RunWidget::writevalueToINTXMLFile(QDomDocument* doc,QDomElement* ele,QString describe,QString value,QString unit,QString Type)
     {
         QDomAttr visattr = doc->createAttribute("Visible");
         QString vis = "true";//暂时默认为true
         visattr.setValue(vis);
         ele->setAttributeNode(visattr);

         QDomAttr desAttr = doc->createAttribute("Describe");
         desAttr.setValue(describe);
         ele->setAttributeNode(desAttr);

         QDomAttr tyattr = doc->createAttribute("Type");
         tyattr.setValue(Type);
         ele->setAttributeNode(tyattr);

         QDomAttr editattr = doc->createAttribute("Editable");
         editattr.setValue("True");
         ele->setAttributeNode(editattr);

         QDomAttr chineAttr = doc->createAttribute("Chinese");
         chineAttr.setValue("");
         ele->setAttributeNode(chineAttr);

         QDomAttr uattr = doc->createAttribute("Unit");
         uattr.setValue(unit);
         ele->setAttributeNode(uattr);

         QDomAttr attr = doc->createAttribute("Value");
         attr.setValue(value);
         ele->setAttributeNode(attr);

         QDomElement rangeele = doc->createElement("Range");
         QString sr = QString("%1,%2").arg(-1000000).arg(1000000);
         QDomText rtext = doc->createTextNode(sr);
         rangeele.appendChild(rtext);
         ele->appendChild(rangeele);

     }

     void RunWidget::writevalueToBOOLXMLFile(QDomDocument* doc,QDomElement* ele,QString describe,QString value,QString unit,QString Type)
     {
         QDomAttr visattr = doc->createAttribute("Visible");
         QString vis = "true";//暂时默认为true
         visattr.setValue(vis);
         ele->setAttributeNode(visattr);

         QDomAttr desAttr = doc->createAttribute("Describe");
         desAttr.setValue(describe);
         ele->setAttributeNode(desAttr);

         QDomAttr tyattr = doc->createAttribute("Type");
         tyattr.setValue(Type);
         ele->setAttributeNode(tyattr);

         QDomAttr editattr = doc->createAttribute("Editable");
         editattr.setValue("True");
         ele->setAttributeNode(editattr);

         QDomAttr chineAttr = doc->createAttribute("Chinese");
         chineAttr.setValue("");
         ele->setAttributeNode(chineAttr);

         QDomAttr uattr = doc->createAttribute("Unit");
         uattr.setValue(unit);
         ele->setAttributeNode(uattr);

         QDomAttr attr = doc->createAttribute("Value");
         attr.setValue(value);
         ele->setAttributeNode(attr);

     }


     bool RunWidget::parameterBoolW(QDomDocument* doc,QDomElement* parent,Core::FITKParamBool* paraBool)
     {
         if (!paraBool) return false;
         bool value = paraBool->getValue();
         QString boolvalue = "true";
         if(value)boolvalue="true";
         else boolvalue = "false";
         QString describe = paraBool->getDataObjectName();
         QString TextPart,UnitPart;
         this->extractUnitPart(describe,TextPart,UnitPart);
         QDomElement ele;
         ele = doc->createElement("Parameter");
         this->writevalueToBOOLXMLFile(doc,&ele,TextPart,boolvalue,UnitPart,"Bool");
         parent->appendChild(ele);
         return true;
     }

     bool RunWidget::parameterDoubleW(QDomDocument* doc,QDomElement* parent,Core::FITKParamDouble* paraDouble)
     {
         if (!paraDouble) return false;
         double value =paraDouble->getValue();
         QString describe = paraDouble->getDataObjectName();
         QString TextPart,UnitPart;
         this->extractUnitPart(describe,TextPart,UnitPart);
         QDomElement ele;
         ele = doc->createElement("Parameter");
         this->writevalueToMaterialXMLFile(doc,&ele,TextPart,QString::number(value),UnitPart,"Double");
         parent->appendChild(ele);
     }

     bool RunWidget::parameterIntW(QDomDocument* doc,QDomElement* parent,Core::FITKParamInt* paraInt)
     {
         if (!paraInt) return false;
         double value =paraInt->getValue();
         QString describe = paraInt->getDataObjectName();
         QString TextPart,UnitPart;
         this->extractUnitPart(describe,TextPart,UnitPart);
         QDomElement ele;
         ele = doc->createElement("Parameter");
         this->writevalueToINTXMLFile(doc,&ele,TextPart,QString::number(value),UnitPart,"Int");
         parent->appendChild(ele);
     }

     bool RunWidget::parameterComboxW(QDomDocument* doc,QDomElement* parent,Core::FITKParamCombox* paraCombox)
     {
         if (!paraCombox) return false;
         int value =paraCombox->getIndex();
         QStringList option = paraCombox->getValue();
         QString text;
         for (int i = 0; i < option.size(); ++i)
         {
             QString s = option.at(i);
             text.append(s);
             text.append(";");
         }
         text.resize(text.size() - 1);

         QString describe = paraCombox->getDataObjectName();
         QDomElement ele;
         ele = doc->createElement("Parameter");
         QDomAttr visattr = doc->createAttribute("Visible");
         QString vis = "true";//暂时默认为true
         visattr.setValue(vis);
         ele.setAttributeNode(visattr);

         QDomAttr desAttr = doc->createAttribute("Describe");
         desAttr.setValue(describe);
         ele.setAttributeNode(desAttr);

         QDomAttr tyattr = doc->createAttribute("Type");
         tyattr.setValue("Selectable");
         ele.setAttributeNode(tyattr);

         QDomAttr editattr = doc->createAttribute("Editable");
         editattr.setValue("True");
         ele.setAttributeNode(editattr);

         QDomAttr chineAttr = doc->createAttribute("Chinese");
         chineAttr.setValue("");
         ele.setAttributeNode(chineAttr);

         QDomAttr uattr = doc->createAttribute("Unit");
         uattr.setValue("");
         ele.setAttributeNode(uattr);

         QDomAttr attr = doc->createAttribute("CurrentIndex");
         attr.setValue(QString::number(value));
         ele.setAttributeNode(attr);

         QDomElement rangeele = doc->createElement("Option");
         QDomText rtext = doc->createTextNode(text);
         rangeele.appendChild(rtext);
         ele.appendChild(rangeele);

         QDomElement domChinese = doc->createElement("Chinese");
         QDomText textChinese = doc->createTextNode(text);
         domChinese.appendChild(textChinese);
         ele.appendChild(domChinese);

         parent->appendChild(ele);
     }

     void RunWidget::extractUnitPart(QString input ,QString& TextPart ,QString& UnitPart)
     {
         QStringList parts = input.split(' ', QString::SkipEmptyParts);  // 使用空格分割字符串
         if (parts.size() == 1) {
             TextPart = parts[0];  // 如果只有一个部分
             UnitPart = "";
         } else if (parts.size() == 2) {
             TextPart = parts[0];  // 第一个部分是关键字
             UnitPart = parts[1]; // 第二个部分是单位
             UnitPart = UnitPart.mid(1, UnitPart.length() - 2);  // 去掉方括号
         }
     }

//     QDomElement& RunWidget::writeToProjectFile(QDomDocument* doc, QDomElement* parent)
//     {
//         QDomElement mroot = doc->createElement("Materials");
//         const int n = _materialList.size();
//         for (int i = 0; i < n; ++i)
//         {
//             Material* m = _materialList.at(i);
//             m->writeToProjectFile(doc, &mroot);
//         }
//         parent->appendChild(mroot);
//         return mroot;
//     }

     void RunWidget::setFileName(const QString &name)
     {
         _filename = name;
         _file.setFileName(_filename);
     }

}
